<template>
  <div class="draw-image">
    <div class="draw-com" :style="comStyle">
      <img class="image-test" :src="wsSrc" :style="comStyle" />
      <div ref="drawMain" class="draw-main" :style="comStyle"> </div>
    </div>
    <div class="draw-info"> {{ pointsShow }}</div>
  </div>
</template>

<script>
/* eslint-disable @typescript-eslint/no-this-alias */
import Konva from 'konva'
import { useCache } from '@/hooks/web/useCache'

const { wsCache } = useCache()

export default {
  name: 'RevDrawPolygon',
  data() {
    return {
      url: '',
      wsSrc: '',
      // 容器的大小
      container: {
        width: 0,
        height: 0,
        imgWidth: 0,
        imgHeight: 0
      },
      movedSync: Date.now(),
      stage: null,
      layer: null,
      currentGroup: null, // 当前操作的组
      polygonLimit: 4, // 多边形最多几个点，达到后自动闭合多边形
      socket: null
    }
  },
  computed: {
    comStyle() {
      return {
        width: `${this.container.width}px`,
        height: `${this.container.height}px`
      }
    },
    pointsShow() {
      return this.movedSync ? this.getPoints() : []
    }
  },
  beforeUnmount() {
    if (this.socket) {
      this.socket.close()
    }
    if (this.stage) {
      this.stage.destroy()
    }
  },
  methods: {
    loadData(url) {
      var img = new Image()
      img.onload = () => {
        const rect = this.$el.getBoundingClientRect()
        this.container.imgWidth = img.naturalWidth
        this.container.imgHeight = img.naturalHeight
        this.container.width = rect.width
        this.container.height = (rect.width * img.naturalHeight) / img.naturalWidth
        this.initKonva()
        this.url = url
        console.log(img.naturalWidth, img.naturalHeight)
      }
      img.src = url
      this.wsSrc = url
    },
    // 初始化canvas
    initKonva() {
      if (this.stage) {
        this.stage.destroy()
      }
      this.stage = new Konva.Stage({
        container: this.$refs.drawMain,
        width: this.container.width,
        height: this.container.height,
        draggable: false
      })
      this.layer = new Konva.Layer()
      this.stage.add(this.layer)
      this.drawPolygon()

      this.stage.on('contextmenu', (e) => {
        e.evt.preventDefault()
        e.evt.stopPropagation()
      })
    },
    // 画多边形
    drawPolygon() {
      // var image = new Konva.Image({
      //   name: 'image',
      //   x: 0,
      //   y: 0,
      //   image: img,
      //   width: this.container.width,
      //   height: this.container.height,
      //   opacity: 0.6
      // })
      // this.layer.add(image)
      const me = this
      this.stage.on('mousedown', function (e) {
        const button = e.evt.button
        // 如果是右键，清除鼠标选择的多边形
        if (button === 2) {
          if (me.currentGroup) {
            me.currentGroup.destroy()
          }
          e.evt.preventDefault()
          e.evt.stopPropagation()
          return
        }
        // 如果点的线，分组拖动
        if (e.target && e.target.hasName('line')) {
          return
        }
        // 如果点击的是点，可以拖动
        if (e.target && e.target.hasName('circle')) {
          const parent = e.target.getParent()
          if (parent.getType() === 'Group') {
            me.currentGroup = parent
          }
          const circles = (me.currentGroup?.find('Circle') || []).sort((a, b) =>
            a._id > b._id ? 1 : -1
          )
          // 如果点击的第一个点，并且多边形没有闭合，使多边形闭合
          if (
            me.currentGroup &&
            !me.currentGroup.getAttr('closed') &&
            circles[0] &&
            circles.length > 2 &&
            e.target?._id === circles[0]?._id
          ) {
            me.currentGroup.setAttrs({ closed: true })
            const lines = me.currentGroup.find('Line') || []
            lines.forEach((line) => {
              line.setAttrs({ closed: true })
            })
            me.layer.draw()
            me.currentGroup = null
          }
          return
        }

        const x = e.evt.offsetX,
          y = e.evt.offsetY
        const circle = new Konva.Circle({
          x,
          y,
          radius: 6,
          strokeWidth: 2,
          fill: '#fff',
          name: 'circle',
          stroke: 'black',
          draggable: true,
          dragBoundFunc: function (pos) {
            me.movedSync = Date.now()
            return pos
          }
        })
        circle.scale({ x: 1 / me.stage.scaleX(), y: 1 / me.stage.scaleX() })

        if (!me.currentGroup || me.currentGroup.getAttr('closed')) {
          me.currentGroup = new Konva.Group({
            draggable: true
          })
        }

        me.currentGroup.add(circle)
        me.layer.add(me.currentGroup)
        circle.zIndex(0)
        circle.absolutePosition({ x: e.evt.offsetX, y: e.evt.offsetY })
        const lines = me.currentGroup.find('Line') || []
        const circles = me.currentGroup.find('Circle') || []
        const points = circles
          .sort((a, b) => (a._id > b._id ? 1 : -1))
          .map((p) => [p.attrs.x, p.attrs.y])
          .flat()
        if (circles.length > 1 && lines.length < 1) {
          var poly = new Konva.Line({
            name: 'line',
            points,
            stroke: '#000',
            strokeWidth: 2,
            dash: [5],
            closed: false
          })
          var poly2 = new Konva.Line({
            name: 'line',
            points,
            stroke: '#fff',
            strokeWidth: 3,
            dash: [5],
            closed: false
          })
          me.currentGroup.add(poly2)
          me.currentGroup.add(poly)
          poly2.zIndex(1)
          poly.zIndex(2)
        } else {
          lines.forEach((line) => {
            line.setAttrs({
              points: circles.map((p) => [p.attrs.x, p.attrs.y]).flat(),
              closed: me.polygonLimit && circles.length >= me.polygonLimit
            })
          })
          if (me.polygonLimit && circles.length >= me.polygonLimit) {
            me.currentGroup.setAttrs({ closed: true })
          }
        }
        me.layer.draw()
      })

      // 鼠标移动
      this.stage.on('mousemove', function () {})

      // 鼠标放开
      this.stage.on('mouseup', function () {
        if (me.currentGroup) {
          me.currentGroup.children.forEach((c) => {
            if (c.hasName('circle')) {
              c.zIndex(3)
            }
          })
          const lines = me.currentGroup.find('Line') || []
          const circles = me.currentGroup.find('Circle') || []
          lines.forEach((line) => {
            line.setAttrs({
              points: circles
                .sort((a, b) => (a._id > b._id ? 1 : -1))
                .map((p) => [p.attrs.x, p.attrs.y])
                .flat()
            })
          })
        }
      })
    },

    drawPolygonByPoints(inPoints = []) {
      if (!this.layer) {
        return
      }
      const me = this
      const scale = this.container.imgWidth / this.container.width
      const points = inPoints.map(([x, y]) => [
        Number((x / scale).toFixed(2)),
        Number((y / scale).toFixed(2))
      ])
      const group = new Konva.Group({
        draggable: true,
        closed: true
      })
      me.layer.add(group)
      var poly = new Konva.Line({
        name: 'line',
        points: points.flat(),
        stroke: '#000',
        strokeWidth: 2,
        dash: [5],
        closed: true
      })
      var poly2 = new Konva.Line({
        name: 'line',
        points: points.flat(),
        stroke: '#fff',
        strokeWidth: 3,
        dash: [5],
        closed: true
      })
      group.add(poly2)
      group.add(poly)
      poly2.zIndex(0)
      poly.zIndex(1)

      points.forEach((point) => {
        const [x, y] = point
        const circle = new Konva.Circle({
          x,
          y,
          radius: 6,
          strokeWidth: 2,
          fill: '#fff',
          name: 'circle',
          stroke: 'black',
          draggable: true,
          dragBoundFunc: function (pos) {
            me.movedSync = Date.now()
            return pos
          }
        })
        // circle.scale({ x: 1 / me.stage.scaleX(), y: 1 / me.stage.scaleX() })
        group.add(circle)
        circle.zIndex(2)
        circle.absolutePosition({ x, y })
      })
      me.layer.draw()
    },

    getPoints() {
      const groups = this.layer?.find('Group') || []
      const scale = this.container.imgWidth / this.container.width
      return groups
        .filter((g) => g.getAttr('closed'))
        .map((group) =>
          group
            .find('Circle')
            .sort((a, b) => (a._id > b._id ? 1 : -1))
            .map((c) => {
              const pos = c.absolutePosition()
              return [Number((pos.x * scale).toFixed(2)), Number((pos.y * scale).toFixed(2))]
            })
        )
    },

    // 回显点位
    setPolygonPoints(points = []) {
      const groups = this.layer?.find('Group') || []
      groups.forEach((g) => {
        g.destroy()
      })
      points.forEach((ps) => {
        this.drawPolygonByPoints(ps)
      })
      this.movedSync = Date.now()
    },

    // 获取点位
    getPolygonPoints() {
      this.playWs()
      return this.getPoints()
    },

    playWs() {
      if (this.socket) {
        this.socket.close()
      }
      const token = wsCache.get('Admin-Token') || 'test'
      let wsUrl = location.origin.replace('http', 'ws')
      if (['localhost', '127.0.0.1'].includes(location.hostname)) {
        wsUrl = 'ws://gpu001.revai.cn:8085'
      }
      const socket = new WebSocket(`${wsUrl}/ws?token=${token}`)
      // Listen for messages
      const me = this
      socket.addEventListener('message', function (event) {
        const data = event.data
        // console.log(data)
        me.wsSrc = `data:image/jpeg;base64,${data}`
      })
      this.socket = socket
    }
  }
}
</script>

<style lang="less" scoped>
.draw-image {
  width: 100%;
  height: 100%;

  .draw-com {
    position: relative;
  }

  .draw-main {
    position: absolute;
    left: 0;
    top: 0;
  }

  .draw-tool {
    height: 50px;
  }

  .draw-info {
    height: 100px;
  }
}
</style>
